package com.hd123.rumba.qt.result;

import java.io.IOException;
import java.io.Serializable;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Enumeration;
import java.util.Hashtable;

import org.apache.log4j.Logger;

import com.hd123.rumba.qt.def.QueryDefinition;
import com.hd123.rumba.qt.def.SQLCriteria;
import com.hd123.rumba.qt.run.Interpretor;
import com.hd123.rumba.runtime.HibernateSession;

public class QueryCriteria implements Serializable {

  /**
   * 从params中查找key为qtQuery_<row>.<column>的entry, 将其value放到sg[row][colum]中
   * 条件值row从1开始, column从0开始.
   * 
   * @param params
   * @see QueryResultDescription#getCriteria()
   * 
   */
  public void setCriteria(Hashtable params) {
    if (sg == null)
      sg = new String[QueryDefinition.MAXROWCOUNT][query.getCriterias().size()];
    Enumeration keys = params.keys();
    while (keys.hasMoreElements()) {
      String key = (String) keys.nextElement();
      if (key.startsWith(PARAM_QUERY_PREFIX)) {
        String s = key.substring(PARAM_QUERY_PREFIX.length());
        int idx = s.indexOf('.');
        int row = Integer.parseInt(s.substring(0, idx));
        int column = Integer.parseInt(s.substring(idx + 1));
        String v = (String) params.get(key);
        if (v.trim().length() > 0)
          sg[row][column] = v;
      } else if (key.startsWith(PARAM_QUERY_CHECK)) {
        String s = key.substring(PARAM_QUERY_CHECK.length());
        int idx = s.indexOf('.');
        int row = Integer.parseInt(s.substring(0, idx));
        int column = Integer.parseInt(s.substring(idx + 1));
        String v = (String) params.get(key);
        if (v.trim().length() > 0)
          sg[row][column] = "yes";
        else
          sg[row][column] = "no";
      }
    }
  }

  /**
   * @return
   * @see QueryResultDescription#getCriteria()
   */
  public Hashtable getCriteria() throws Exception {
    Hashtable h = new Hashtable();
    if (sg == null)
      sg = query.getSg();

    // 第0行是条件名称
    int row = 0;
    for (int column = 0; column < sg[row].length; ++column) {
      String value = query.getSg()[row][column];
      if (value == null)
        value = "";
      h.put(PARAM_QUERY_PREFIX + row + "." + column, value);
    }

    for (row = 1; row < sg.length; ++row) {
      for (int column = 0; column < sg[row].length; ++column) {
        String name = null;
        String value = sg[row][column];
        if (value == null)
          value = "";
        h.put(PARAM_QUERY_PREFIX + row + "." + column, value);
        // pick name and values
        if (row != 1)
          continue; // 只需要构造1份候选值列表就可以了.
        /** ***********预设条件的bug*********** */
        if (column >= query.getCriterias().size())
          continue;
        /** ********************************* */
        SQLCriteria c = (SQLCriteria) query.getCriterias().get(column);
        if (c.getPickNames().size() == 2
            && "#TABLE".equalsIgnoreCase((String) c.getPickNames().get(0))) {
          // 查询数据库, 构造候选值
          // 如果PickName[0] = #TABLE, PickValue[0] = select * from "dbtable"
          // PickName[1] = display field name, PickValue[1] = value field name
          String errmsg = "查询定义中指定从数据库中构造\"" + c.getLeft() + "\"的候选条件, ";
          if (c.getPickValues().size() != 2)
            throw new Exception(errmsg + "但是没有提供作为候选值的列名");
          String sql = (String) c.getPickValues().get(0);
          String displayField = ((String) c.getPickNames().get(1)).toUpperCase();
          String valueField = ((String) c.getPickValues().get(1)).toUpperCase();
          Connection conn = HibernateSession.getSession().connection();
          PreparedStatement ps = null;
          ResultSet rs = null;
          try {
            Logger.getLogger(this.getClass()).debug("executing " + sql);
            sql = Interpretor.getInterpretor(this.getQuery().getSessionValues()).interpret(sql);
            ps = conn.prepareStatement(sql);
            rs = ps.executeQuery();
            int j = 0;
            for (; rs.next(); ++j) {
              // name = (String) rs.getObject(displayField);
              Object nameObj = rs.getObject(displayField);
              if (nameObj == null)
                name = "";
              else {
                if (nameObj instanceof String)
                  name = (String) nameObj;
                else
                  name = nameObj.toString();
              }

              Object valueObj = rs.getObject(valueField);

              if (valueObj == null)
                value = "";
              else {
                if (valueObj instanceof String)
                  value = (String) valueObj;
                else
                  value = valueObj.toString();
              }
              if (value != null && value.trim().length() > 0) {
                h.put(PARAM_QUERY_PICK_NAME_KEY + column + "." + j, name);
                h.put(PARAM_QUERY_PICK_VALUE_KEY + column + "." + j, value);
              }
            }
            h.put("qtQueryPickItemCount." + column, new Integer(j));
          } catch (Exception e) {
            errmsg = errmsg + e.getMessage() + "<br>pickNames[0]=#table<br>pickValues[0]=" + sql
                + "<br>pickNames[1]=" + displayField + "<br>pickValues[1]=" + valueField;
            Logger.getLogger(this.getClass()).error(errmsg);
            throw new Exception(errmsg);
          } finally {
            if (rs != null)
              rs.close();
            if (ps != null)
              ps.close();
          }
        } else {
          // 固定的候选值
          for (int i = 0, j = 0; i < c.getPickNames().size(); ++i) {
            Object nameObj = (String) c.getPickNames().get(i);
            if (nameObj == null)
              name = "";
            else {
              if (nameObj instanceof String)
                name = (String) nameObj;
              else
                name = nameObj.toString();
            }
            Object valueObj = (String) c.getPickValues().get(i);
            if (valueObj == null)
              value = "";
            else {
              if (valueObj instanceof String)
                value = (String) valueObj;
              else
                value = valueObj.toString();
            }
            if (value != null && value.trim().length() > 0) {
              h.put(PARAM_QUERY_PICK_NAME_KEY + column + "." + j, name);
              h.put(PARAM_QUERY_PICK_VALUE_KEY + column + "." + j, value);
              ++j;
            }
          }
          h.put("qtQueryPickItemCount." + column, new Integer(c.getPickNames().size()));
        }
      }
    }

    return h;
  }

  /**
   * 组装显示用的文本
   * 
   * @return
   */
  public String getInfo() {
    StringBuffer sb = new StringBuffer();
    boolean isFirstLine = true;
    for (int row = 1; row < sg.length - 1; ++row) {
      StringBuffer line = new StringBuffer();
      for (int col = 0; col < sg[row].length; ++col) {
        if (sg[row][col] != null && sg[row][col].trim().length() > 0) {
          if (line.length() > 0)
            line.append("并且");
          line.append(sg[0][col]);
          line.append(sg[row][col]);
        }
      }
      if (line.length() > 0) {
        if (sb.length() > 0) {
          if (isFirstLine) {
            sb.insert(0, "(");
            sb.append(")");
            isFirstLine = false;
          }
          sb.append("或者");
          sb.append("(");
          sb.append(line);
          sb.append(")");
        } else
          sb.append(line);
      }
    }
    return sb.toString();
  }

  public String debugInfo() {
    StringBuffer sb = new StringBuffer();
    sb.append(getClass().getName() + "\n");
    if (sg != null)
      for (int i = 0; i < sg.length; ++i) {
        sb.append("{");
        for (int j = 0; j < sg[i].length; ++j) {
          if (j > 0)
            sb.append(",");
          sb.append("(");
          sb.append(sg[i][j]);
          sb.append(")");
        }
        sb.append("}\n");
      }
    return sb.toString();
  }

  private transient QueryDefinition query;
  private String[][] sg = null;

  public void setQuery(QueryDefinition query) {
    this.query = query;
    int rowCount = query.getSg().length;
    int colCount = query.getSg()[0].length;
    if (sg == null)
      sg = new String[rowCount][colCount];
    for (int col = 0; col < colCount; ++col)
      sg[0][col] = query.getSg()[0][col];
  }

  public QueryDefinition getQuery() {
    return query;
  }

  public String[][] getSg() {
    return sg;
  }

  public void setSg(String[][] sg) {
    this.sg = sg;
  }

  public boolean isSame(QueryCriteria qc) {
    if (sg == null) {
      if (qc.getSg() == null)
        return true;
      else
        return false;
    } else if (qc.getSg() == null)
      return false;
    if (sg.length != qc.getSg().length)
      return false;
    for (int i = 0; i < sg.length; ++i) {
      if (sg[i].length != qc.getSg()[i].length)
        return false;
      for (int j = 0; j < sg[i].length; ++j) {
        if (sg[i][j] == null) {
          if (qc.getSg()[i][j] != null)
            return false;
        } else {
          if (!sg[i][j].equals(qc.getSg()[i][j]))
            return false;
        }
      }
    }
    return true;
  }

  private void writeObject(java.io.ObjectOutputStream out) throws IOException {
    out.writeObject(sg);
  }

  private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
    sg = (String[][]) in.readObject();
  }

  public static final String PARAM_QUERY_PREFIX = "qtQuery_";
  public static final String PARAM_QUERY_PICK_NAME_KEY = "qtQueryPickName_";
  public static final String PARAM_QUERY_PICK_VALUE_KEY = "qtQueryPickValue_";
  public static final String PARAM_QUERY_CHECK = "qtQueryCheck_";
}
